import streamlit as st
import streamlit_antd_components as sac
import datetime
import io
import csv
import uuid
import ujson as json
from data_utils import convert_numeric_type, save_draft_inputs, get_user_drafts, load_draft_inputs, delete_draft, load_calculators
import matplotlib.pyplot as plt
from pdf_utils import generate_pdf_download_button
from admin.calculator_utils import sort_targets, display_calculation_history, execute_calculator
from admin.menu_manager import MenuManager
from data_utils import load_tasks, save_task, format_calc_id


def format_timestamp(timestamp_str: str) -> str:
    """
    将ISO格式时间戳转换为易读形式

    Args:
        timestamp_str: ISO格式时间戳字符串，如"2025-01-21T16:04:55.686982"

    Returns:
        str: 格式化后的时间字符串，如"2025年01月21日 16:04:55"
    """
    try:
        # 解析时间戳
        dt = datetime.datetime.fromisoformat(timestamp_str)
        # 格式化为易读形式
        return dt.strftime("%Y年%m月%d日 %H:%M:%S")
    except ValueError:
        # 如果解析失败，返回原始字符串
        return timestamp_str

def user_page():
    # 首次访问初始化默认视图
    if "user_view" not in st.session_state:
        st.session_state.user_view = "calculator"

    # 记录上一次选择的计算器
    if "last_selected_calc" not in st.session_state:
        st.session_state.last_selected_calc = None

    # 使用load_calculators从数据库加载计算器
    calculators = load_calculators()

    # 筛选可用的计算器
    active_calcs = []
    for calc in calculators:
        if calc.status != "active":
            continue
        access_control = calc.access_control or {"type": "all"}
        if access_control["type"] == "all":
            active_calcs.append(calc)
        elif access_control["type"] == "restricted":
            if st.session_state.username in access_control.get("allowed_users", []):
                active_calcs.append(calc)

    if not active_calcs:
        st.warning("暂无可用的计算器，请联系管理员。")
        return

    # 获取菜单管理器实例
    menu_manager = MenuManager.get_instance(reset=True)
    menu_manager.register(
        "view_history",
        history_page,
        label="查看计算历史",
        icon="clipboard-data-fill",
    )
    menu_manager.register(
        "calc_history_divider",
        lambda: None,
        type='divider'
    )

    menu_manager.register(
        "calculator_list",
        lambda: None,  # 父菜单不需要处理函数
        label="选择计算器",
        type="group",
        children=[]  # 先创建空的子菜单列表
    )

    # 构建菜单项
    for calc in active_calcs:
        menu_manager.register(
            f'calc_{calc.name}',
            lambda calc=calc: calc_page(active_calcs, calc.name),
            label=calc.name,
            icon='calculator-fill',
            parent='calculator_list'
        )

    menu_manager.show_menu(index=3) # 默认打开第一个激活的计算器，index=3是因为前面有3个菜单项，可以根据历史记录来调整index


def history_page():
    st.subheader("计算历史记录")

    # 获取当前用户的所有计算记录
    # 如果是复核员，获取所有用户的记录
    is_reviewer = False
    calculator_names = set()
    all_users = set()
    # 构建计算器选项映射，包含ID信息
    calculator_options = {"全部": "全部"}

    # 先加载所有计算器，检查用户是否是任意计算器的复核员
    calculators = load_calculators()
    for calc in calculators:
        if st.session_state.username in (calc.access_control.get("reviewers", [])):
            is_reviewer = True
            break

    if is_reviewer:
        user_tasks = load_tasks()  # 加载所有任务
        for task in user_tasks:
            calculator_names.add(task["calculator_name"])
            all_users.add(task["username"])
            # 为每个计算器名称添加ID信息
            for calc in calculators:
                if calc.name == task["calculator_name"]:
                    calculator_options[f"{calc.name} (ID: {format_calc_id(calc.id)})"] = calc.name
    else:
        user_tasks = load_tasks(username=st.session_state.username)
        for task in user_tasks:
            calculator_names.add(task["calculator_name"])
            # 为每个计算器名称添加ID信息
            for calc in calculators:
                if calc.name == task["calculator_name"]:
                    calculator_options[f"{calc.name} (ID: {format_calc_id(calc.id)})"] = calc.name

    if not user_tasks:
        st.info("暂无计算记录")
        return

    # 筛选条件区域
    col1, col2 = st.columns(2)

    with col1:
        start_date = st.date_input(
            "开始日期",
            value=None,
            key="history_start_date"
        )

    with col2:
        end_date = st.date_input(
            "结束日期",
            value=None,
            key="history_end_date"
        )

    # 复核员可以看到用户筛选
    if is_reviewer:
        selected_user = st.selectbox(
            "用户筛选",
            ["全部"] + sorted(list(all_users)),
            key="user_filter"
        )

    # 修改计算器名称筛选
    selected_calculator_display = st.selectbox(
        "计算器名称",
        options=list(calculator_options.keys()),
        key="calculator_filter"
    )
    selected_calculator = calculator_options[selected_calculator_display]

    # 应用筛选条件
    filtered_tasks = user_tasks

    if start_date:
        filtered_tasks = [
            t for t in filtered_tasks
            if datetime.datetime.strptime(t["timestamp"].split()[0], "%Y-%m-%d").date() >= start_date
        ]
    if end_date:
        filtered_tasks = [
            t for t in filtered_tasks
            if datetime.datetime.strptime(t["timestamp"].split()[0], "%Y-%m-%d").date() <= end_date
        ]
    if selected_calculator != "全部":
        filtered_tasks = [
            t for t in filtered_tasks
            if t["calculator_name"] == selected_calculator
        ]
    # 添加用户筛选条件
    if is_reviewer and selected_user != "全部":
        filtered_tasks = [
            t for t in filtered_tasks
            if t["username"] == selected_user
        ]

    # 显示过滤后的记录
    st.write(f"共找到 {len(filtered_tasks)} 条记录")

    # 反转列表以便最新的记录显示在前面
    filtered_tasks = filtered_tasks[::-1]

    # 显示历史记录（如果是复核员，显示用户名信息）
    display_calculation_history(filtered_tasks, show_username=is_reviewer)

    # 导出功能
    if st.button("导出筛选结果为 CSV"):
        csv_buffer = io.StringIO()
        fieldnames = [
            "calculator_name",
            "timestamp",
            "inputs",
            "output",
        ]
        writer = csv.DictWriter(csv_buffer, fieldnames=fieldnames)
        writer.writeheader()
        for item in filtered_tasks:
            writer.writerow(
                {
                    "calculator_name": item["calculator_name"],
                    "timestamp": item["timestamp"],
                    "inputs": json.dumps(item["inputs"], ensure_ascii=False),
                    "output": item["output"],
                }
            )
        csv_data = csv_buffer.getvalue().encode("utf-8")
        st.download_button(
            label="下载CSV文件",
            data=csv_data,
            file_name="my_calc_history.csv",
            mime="text/csv",
        )

def calc_page(active_calcs, selected_calc_name):
    """计算器页面"""
    selected_calc = next(
        (c for c in active_calcs if c.name == selected_calc_name), None
    )

    # 清除之前计算器的草稿数据
    if "current_draft_id" in st.session_state:
        del st.session_state.current_draft_id
    if "current_draft_data" in st.session_state:
        del st.session_state.current_draft_data

    st.subheader(selected_calc.name)
    sac.tags([sac.Tag(label=f"流水号: {format_calc_id(selected_calc.id)}", color="blue", icon=sac.BsIcon("hash"))])

    # 将计算和历史记录分成两个标签页
    calc_tabs = st.tabs(["计算", "历史记录"])

    # --- 计算标签页 ---
    with calc_tabs[0]:
        # 获取当前用户当前计算器的草稿
        drafts = get_user_drafts(
            st.session_state.username,
            selected_calc.id
        )

        # 只有存在草稿时才显示选择框
        if drafts:
            draft_options = {
                format_timestamp(d['timestamp']): d['id']
                for d in drafts
            }
            selected_draft = st.selectbox(
                "加载已保存的输入",
                ["不加载草稿"] + list(draft_options.keys())
            )
            if selected_draft != "不加载草稿":
                draft_id = draft_options[selected_draft]
                draft_data = load_draft_inputs(draft_id)
                if draft_data:
                    st.session_state.current_draft_id = draft_id
                    st.session_state.current_draft_data = draft_data

        with st.form("calc_execute_form"):
            user_inputs = {}

            # 收集所有不同的 target
            targets = set()
            for field in selected_calc.inputs:
                target = field.get("target", "其他")  # 如果没有指定target，归类为"其他"
                if target is None:
                    target = "其他" # 如果target为None，归类为"其他"
                targets.add(target)

            if len(targets) > 1:  # 如果有多个target才创建tabs
                # 按 target 分组并筛选有效字段
                valid_targets = {}
                for target in sort_targets(targets):
                    # 获取当前 target 的所有字段
                    target_fields = [
                        f for f in selected_calc.inputs
                        if (f.get("target", "其他") or "其他") == target
                    ]
                    # 筛选出 input_mode 不是"非输入项"的字段
                    valid_fields = [
                        field for field in target_fields
                        if field.get("input_mode") != "非输入项"
                    ]
                    # 只有当有可显示的字段时，才将该 target 加入到有效列表中
                    if valid_fields:
                        valid_targets[target] = valid_fields

                # 只为有效的 target 创建 tabs
                if valid_targets:
                    input_tabs = st.tabs(list(valid_targets.keys()))
                    # 在每个 tab 中显示对应的输入字段
                    for i, target in enumerate(valid_targets.keys()):
                        with input_tabs[i]:
                            # 使用已筛选的有效字段
                            target_fields = valid_targets[target]

                            # 创建足够的行来容纳所有字段
                            for j in range(0, len(target_fields), 2):
                                col1, col2 = st.columns(2)
                                # 渲染第一个字段
                                render_input_field(target_fields[j], user_inputs, col1, selected_calc.id)
                                # 如果有第二个字段，渲染它
                                if j + 1 < len(target_fields):
                                    render_input_field(target_fields[j + 1], user_inputs, col2, selected_calc.id)

            else:
                # 如果只有一个target，筛选并显示有效输入字段
                valid_fields = [
                    field for field in selected_calc.inputs
                    if field.get("input_mode") != "非输入项"
                ]
                # 创建足够的行来容纳所有字段
                for i in range(0, len(valid_fields), 2):
                    col1, col2 = st.columns(2)
                    # 渲染第一个字段
                    render_input_field(valid_fields[i], user_inputs, col1, selected_calc.id)
                    # 如果有第二个字段，渲染它
                    if i + 1 < len(valid_fields):
                        render_input_field(valid_fields[i + 1], user_inputs, col2, selected_calc.id)

            # 修改提交按钮部分，使用两列放置两个按钮

            with st.container(key="calc_submit_buttons"):
                empt1, col1, col2 = st.columns([3,1,1])
                with col1:
                    save_draft = st.form_submit_button("保存为草稿")
                with col2:
                    submitted = st.form_submit_button("执行计算", type="primary")

            # 处理草稿保存
            if save_draft:
                draft_id = str(uuid.uuid4())
                save_draft_inputs(
                    draft_id,
                    user_inputs,
                    selected_calc.id,
                    st.session_state.username
                )
                st.toast("已保存草稿！")
                st.rerun()

            # 处理计算执行
            if submitted:
                # 执行计算器
                calc_result, success = execute_calculator(selected_calc.code, user_inputs, st)
                if success:
                    # 创建新任务并保存到数据库
                    task_id = save_task({
                        "calculator_id": selected_calc.id,
                        "calculator_name": selected_calc.name,
                        "username": st.session_state.username,
                        "timestamp": datetime.datetime.now().isoformat(sep=" ", timespec="seconds"),
                        "inputs": user_inputs,
                        "output": calc_result
                    })

                    # 计算成功后，如果是从草稿加载的，删除对应的草稿
                    if "current_draft_id" in st.session_state:
                        delete_draft(st.session_state.current_draft_id)
                        del st.session_state.current_draft_id
                        del st.session_state.current_draft_data

                    # 保存计算结果到 session_state
                    st.session_state.current_calc_result = {
                        'calc_name': selected_calc.name,
                        'inputs': user_inputs,
                        'output': calc_result,
                        'timestamp': datetime.datetime.now().isoformat(sep=" ", timespec="seconds"),
                        'task_id': task_id  # 添加任务ID
                    }

                    st.toast(f"计算成功! 任务ID: {task_id}")

        # 表单外部显示下载按钮
        if "current_calc_result" in st.session_state:
            result = st.session_state.current_calc_result
            generate_pdf_download_button(
                st,
                task_id=result.get('task_id'),
                button_text="导出为PDF",
                position="calc_submit"
            )
            # 清理结果
            del st.session_state.current_calc_result

    # --- 历史记录标签页 ---
    with calc_tabs[1]:
        # 检查当前用户是否为该计算器的复核员
        is_reviewer = st.session_state.username in (selected_calc.access_control.get("reviewers", []))

        # 从数据库加载历史记录
        if is_reviewer:
            # 复核员可以查看所有记录
            filtered = load_tasks(calculator_id=selected_calc.id)
        else:
            # 普通用户只能查看自己的记录
            filtered = load_tasks(
                calculator_id=selected_calc.id,
                username=st.session_state.username
            )

        # 显示历史记录
        if not filtered:
            st.info("暂无此计算器的历史记录")
        else:
            st.markdown(f"共找到 {len(filtered)} 条记录")

            # 如果是复核员，添加用户筛选功能
            if is_reviewer:
                all_users = list({t["username"] for t in filtered})
                selected_user = st.selectbox(
                    "选择用户查看记录",
                    ["所有用户"] + all_users
                )
                if selected_user != "所有用户":
                    filtered = [t for t in filtered if t["username"] == selected_user]

            # 添加时间范围筛选
            col1, col2 = st.columns(2)
            with col1:
                start_date = st.date_input(
                    "开始日期",
                    value=None,
                    key=f"calc_history_start_date_{selected_calc.id}"
                )
            with col2:
                end_date = st.date_input(
                    "结束日期",
                    value=None,
                    key=f"calc_history_end_date_{selected_calc.id}"
                )

            # 应用时间筛选
            if start_date:
                filtered = [
                    t for t in filtered
                    if datetime.datetime.strptime(t["timestamp"].split()[0], "%Y-%m-%d").date() >= start_date
                ]
            if end_date:
                filtered = [
                    t for t in filtered
                    if datetime.datetime.strptime(t["timestamp"].split()[0], "%Y-%m-%d").date() <= end_date
                ]

            # 显示筛选后的记录
            st.markdown(f"筛选后找到 {len(filtered)} 条记录")
            # 如果是复核员，显示用户名信息
            display_calculation_history(filtered, show_username=is_reviewer)

            # 导出功能
            if st.button("导出历史记录"):
                csv_buffer = io.StringIO()
                fieldnames = [
                    "timestamp",
                    "inputs",
                    "output",
                ]
                writer = csv.DictWriter(csv_buffer, fieldnames=fieldnames)
                writer.writeheader()
                for item in filtered:
                    writer.writerow(
                        {
                            "timestamp": item["timestamp"],
                            "inputs": json.dumps(item["inputs"], ensure_ascii=False),
                            "output": item["output"],
                        }
                    )
                csv_data = csv_buffer.getvalue().encode("utf-8")
                st.download_button(
                    label="下载CSV文件",
                    data=csv_data,
                    file_name=f"{selected_calc.name}_history.csv",
                    mime="text/csv",
                )

def render_input_field(field, user_inputs, column, calculator_id):
    """渲染单个输入字段"""
    if field.get("input_mode") == "非输入项":
        return
    iname = field.get("name", "")
    title = field.get("title", "")
    ptype = field.get("type", "string")

    # 创建唯一的输入字段key
    field_key = f"{calculator_id}_{iname}"

    # 获取草稿数据作为默认值
    default_value = None
    if "current_draft_data" in st.session_state and st.session_state.current_draft_data:
        default_value = st.session_state.current_draft_data.get(iname)

    with column:
        if ptype == "number":
            minimum = convert_numeric_type(field.get("minimum"), "number")
            maximum = convert_numeric_type(field.get("maximum"), "number")
            step = convert_numeric_type(field.get("step"), "number") or 0.1

            # 使用草稿值或字段默认值
            if default_value is not None:
                default = convert_numeric_type(default_value, "number")
            else:
                default = convert_numeric_type(field.get("default"), "number") or 0.0

            # 根据step值确定输入精度
            decimal_places = len(str(step).split('.')[-1]) if '.' in str(step) else 0

            user_inputs[iname] = st.number_input(
                f"{iname} - {title}",
                min_value=minimum,
                max_value=maximum,
                step=step,
                value=default,
                format=f"%.{decimal_places}f",
                key=field_key
            )
        elif ptype == "integer":
            minimum = convert_numeric_type(field.get("minimum"), "integer")
            maximum = convert_numeric_type(field.get("maximum"), "integer")
            step = convert_numeric_type(field.get("step"), "integer") or 1

            if default_value is not None:
                default = convert_numeric_type(default_value, "integer")
            else:
                default = convert_numeric_type(field.get("default"), "integer") or 0

            user_inputs[iname] = st.number_input(
                f"{iname} - {title}",
                min_value=minimum,
                max_value=maximum,
                step=step,
                value=default,
                key=field_key
            )
        else:
            default = str(default_value) if default_value is not None else ""
            user_inputs[iname] = st.text_input(
                f"{iname} - {title}",
                value=default,
                key=field_key
            )
